<script>
import {getRegionApi} from "@/api/address"
import {mapActions, mapState} from "vuex"

export default {
  name: "AddressEdit",
  async onLoad(options) {
    // 因为后端返回的 id 是数字，为了匹配类型，前端也得把 url 收到的 id 转为数字
    // 因为现在是在编辑地址，所以这个 addressId 是一定存在的，不用做非空处理
    const addressId = Number(options.addressId)
    this.addressId = addressId

    // 获取后端的省市区数据
    // 请求地址列表
    // 使用 Promise.all 并行请求
    const [regionRes, _] = await Promise.all([
      getRegionApi(),
      this.getAddressList()
    ])

    // 此时 getAddressList 执行完，this.addressList 肯定是存在的
    this.currentAddress = this.addressList.find(item => item.address_id === addressId)

    this.originAreaList = regionRes.data.list

    // 初始化组件需要的省市区数据，并且生成旧的省市区和新的省市区数据的映射
    this.initAreaList()
    // 上面的 initAreaList 是组件要用的，下面的 initMyAreaList 是我要用的地址数据
    this.initMyAddressList()
  },
  data() {
    return {
      addressId: 0, // 地址id，路由携带过来的查询参数,记得转为数字
      originAreaList: {}, // 原始省市区列表
      // 存储新旧ID的映射关系，idMapping 在初始的时候只有 province，city，region 是响应式的
      // 后续往 idMapping 里加的东西都不是响应式的，这就是Vue2的响应式缺陷
      // 在 addressInfo 依赖了 idMapping.region 里的一个数据
      // 想着 idMapping.region 更新会触发这个 getters，结果 idMapping.region 里的东西是非响应式的
      // 那也就说明不会重新触发 addressInfo 这个 getters
      idMapping: {
        province: {}, // { oldId: newId }
        city: {},
        region: {}
      },
      areaList: {}, // 组件要求传递的省市区数据
      isShowPanel: false,
      currentAddress: {}, // 当前地址对象
      myAddressList: {}, // 我要用的地址数据
      errors: { // 错误提示
        name: '',
        tel: '',
        area: '',
        addressDetail: ''
      },
    }
  },
  computed: {
    ...mapState('address', ['addressList']), // 地址列表数据
  },
  methods: {
    ...mapActions('address', ['getAddressList', 'editAddress']), // 请求地址列表数据 和 编辑地址 的方法
    // 传递给组件的省市区数据
    initAreaList() {
      // 没有后端的省市区数据直接返回空对象
      if (!this.originAreaList) return {}

      const areaList = {
        province_list: {},
        city_list: {},
        county_list: {}
      }

      // 创建临时的 idMapping，等会填充完把 data 中的 idMapping 整个换掉，确保响应式
      // addressInfo 这个 getters 会在 idMapping 整个换掉的时候再次触发，这个方案更好
      // 其实 $set 方案也不错，$set 往一个对象obj加入一个带有 get 和 set 的属性 a，并且会触发对象 obj 的所有依赖
      // 如果 obj 的依赖中有使用了 obj.a 的地方，此时属性 a 趁机收集自己的依赖，也是一个完美的方案
      const idMappingTemp = {
        province: {}, // { oldId: newId } 其实就是后端返回的 id 和组件要求的 id 不一致
        city: {},
        region: {}
      }

      let provinceIndex = 1
      const provinces = this.originAreaList

      Object.values(provinces).forEach(province => {
        const provinceId = String(provinceIndex).padStart(2, '0')
        const provinceCode = provinceId + '0000'
        areaList.province_list[provinceCode] = province.name

        // 保存新旧省份ID的映射，这里的 provinceId 是只有两位的，provinceCode 是有六位的
        idMappingTemp.province[province.id] = provinceCode

        if (province.city) {
          let cityIndex = 1
          Object.values(province.city).forEach(city => {
            const cityId = String(cityIndex).padStart(2, '0')
            const cityCode = provinceId + cityId + '00'
            areaList.city_list[cityCode] = city.name

            // 保存新旧城市ID的映射
            idMappingTemp.city[city.id] = cityCode

            if (city.region) {
              let regionIndex = 1
              Object.values(city.region).forEach(region => {
                const regionId = String(regionIndex).padStart(2, '0')
                const regionCode = provinceId + cityId + regionId
                areaList.county_list[regionCode] = region.name

                // 保存新旧区县ID的映射，必须6位数字才能标识一个 region
                idMappingTemp.region[region.id] = regionCode

                regionIndex++
              })
            }
            cityIndex++
          })
        }
        provinceIndex++
      })

      this.idMapping = idMappingTemp
      this.areaList = areaList
    },
    // 获取到当前地址对象对应的省市区数据
    initMyAddressList() {
      const obj = this.currentAddress
      // 后端的省市区数据只要存在，就一定存在映射，旧的编码映射新的编码，areaCode 作为旧编码映射的新编码，一定存在的
      const areaCode = this.idMapping.region[obj.region_id]

      this.myAddressList = {
        name: obj.name,
        tel: obj.phone,
        addressDetail: obj.detail,
        province: obj.region?.province,
        city: obj.region?.city,
        county: obj.region?.region,
        area: [obj.region?.province, obj.region?.city, obj.region?.region].filter(Boolean).join('/'),
        province_id: obj.province_id, // 映射前的省份id
        city_id: obj.city_id, // 映射前的城市id
        region_id: obj.region_id, // 映射前的区县id
        areaCode // 映射后的新编码
      }
    },
    onConfirm(obj) {
      // 记住此时 province_id，city_id，region_id，都还没有更新，因为可能还会多次更换 areaCode
      // 等到保存的时候再通过 areaCode 更新 province_id，city_id，region_id
      const arr = obj.detail.values
      const province = this.idMapping.province
      const city = this.idMapping.city
      const region = this.idMapping.region

      this.myAddressList.province = arr[0].name
      this.myAddressList.city = arr[1].name
      this.myAddressList.county = arr[2].name
      this.myAddressList.area = arr.map(item => item.name).join('/')
      this.myAddressList.areaCode = arr[2].code
      this.myAddressList.province_id = Object.keys(province).find(key => province[key] === arr[0].code)
      this.myAddressList.city_id = Object.keys(city).find(key => city[key] === arr[1].code)
      this.myAddressList.region_id = Object.keys(region).find(key => region[key] === arr[2].code)
      this.isShowPanel = false
      // 清除地区错误提示
      this.errors.area = ''
    },
    validateForm() {
      let isValid = true // 默认为 true，如果校验不通过，最后会置为 false
      // 清空之前的错误信息
      Object.keys(this.errors).forEach(field => this.errors[field] = '')

      // 校验姓名
      const name = this.myAddressList.name?.trim() || ''
      if (!name) {
        this.errors.name = '请填写姓名'
        isValid = false
      }

      // 校验手机号（正确格式）
      const tel = this.myAddressList.tel?.trim() || ''
      const telReg = /^1[3-9]\d{9}$/
      if (!tel || !telReg.test(tel)) {
        this.errors.tel = '请输入正确的手机号'
        isValid = false
      }

      // 校验地区选择
      const area = this.myAddressList.area?.trim() || ''
      if (!area) {
        this.errors.area = '请选择地区'
        isValid = false
      }

      // 校验详细地址
      const addressDetail = this.myAddressList.addressDetail?.trim() || ''
      if (!addressDetail) {
        this.errors.addressDetail = '请填写详细地址'
        isValid = false
      }

      return isValid
    },
    // 点击保存按钮
    async onSave() {
      // 先进行表单验证
      if (!this.validateForm()) {
        return
      }

      const myAddressList = this.myAddressList
      // console.log(form)
      // 编辑地址
      await this.editAddress({
        addressId: this.addressId,
        name: myAddressList.name,
        phone: myAddressList.tel,
        regions: [ // 省市区数据
          {
            label: myAddressList.province,
            value: myAddressList.province_id,
          },
          {
            label: myAddressList.city,
            value: myAddressList.city_id,
          },
          {
            label: myAddressList.county,
            value: myAddressList.region_id,
          },
        ],
        detail: myAddressList.addressDetail // 详细地址
      })

      uni.navigateBack() // 保存成功就返回上一级页面
    }
  }
}
</script>

<template>
  <div class="addressEdit">
    <van-nav-bar placeholder fixed title="编辑收货地址" left-arrow @click-left="uni.navigateBack"/>

    <div class="edit">
      <div class="title" style="padding: 12px">
        收货地址
      </div>

      <view class="form">
        <van-field
            :value="myAddressList.name"
            clearable
            label="姓名"
            placeholder="收货人姓名"
            error-message="请填写姓名"
            :error-message="errors.name"
            @input="myAddressList.name = $event.detail"
        />

        <van-field
            :value="myAddressList.tel"
            label="电话"
            placeholder="收货人手机号"
            clearable
            :error-message="errors.tel"
            @input="myAddressList.tel = $event.detail"
        />

        <van-field
            :value="myAddressList.area"
            is-link
            readonly
            label="地区"
            placeholder="请选择所在地区"
            @tap="isShowPanel = true"
            arrow-direction="down"
            :error-message="errors.area"
        />

        <van-field
            :value="myAddressList.addressDetail"
            label="详细地址"
            placeholder="街道门牌、楼层房间号等信息"
            clearable
            :error-message="errors.addressDetail"
            @input="myAddressList.addressDetail = $event.detail"
        />

        <view class="btn">
          <van-button type="primary" round @click="onSave">
            保存
          </van-button>
        </view>
      </view>

    </div>

    <van-action-sheet :show="isShowPanel" @close="isShowPanel = false">
      <van-area
          :value="myAddressList.areaCode"
          :area-list="areaList"
          @cancel="isShowPanel = false"
          @confirm="onConfirm"
      />
    </van-action-sheet>
  </div>
</template>

<style lang="less">
.edit {
  background-color: #f7f8fa;

  .title {
    color: #abb4ba;
    font-size: 14px;
  }

  .form {
    padding: 0 10px;
    border-radius: 10px;
    overflow: hidden;

    .btn {
      margin-top: 20px;
      padding: 0 20px;

      .van-button {
        background: linear-gradient(90deg, #f9211c, #ff6335);
        width: 100%;
        height: 42px;
        color: #fff;
        border-radius: 39px;
        box-shadow: 0 10px 20px 0 rgba(0, 0, 0, .1);
        display: flex;
        justify-content: center;
        align-items: center;
      }
    }

  }
}

</style>
